"""
请假/加班申请相关路由
"""
from flask import request
from flask_restful import Resource
from .. import db
from ..models import LeaveApplication, Employee
from ..utils.helpers import success_response, error_response, handle_errors
from ..utils.flowable_client import FlowableClient
try:
    from server.config.config import Config  # type: ignore
except ModuleNotFoundError:
    from config.config import Config  # type: ignore
from datetime import datetime


class LeaveApplicationResource(Resource):
    """请假/加班申请资源"""
    
    def __init__(self):
        self.flowable_client = FlowableClient(
            Config.FLOWABLE_REST_URL,
            Config.FLOWABLE_REST_USER,
            Config.FLOWABLE_REST_PASSWORD
        )
    
    @handle_errors
    def post(self):
        """提交请假/加班申请"""
        data = request.get_json()
        
        # 支持小时级请假：优先使用 leave_hours；兼容旧字段 leave_days
        # 验证必填字段
        required_fields = ['applicant_id', 'apply_type', 'start_date', 'end_date', 'project_id']
        for field in required_fields:
            if field not in data:
                return error_response(f'缺少必填字段: {field}', 400)

        # 细分请假类型校验（仅 apply_type == 'leave' 时要求）
        allowed_leave_types = [
            'annual', 'personal', 'sick', 'marriage', 'funeral', 'maternity',
            'paternity', 'compensatory', 'other'
        ]
        leave_type_val = None
        if data['apply_type'] == 'leave':
            leave_type_val = data.get('leave_type')
            if not leave_type_val:
                return error_response('缺少 leave_type', 400)
            if leave_type_val not in allowed_leave_types:
                return error_response(f'leave_type 不合法，应为: {", ".join(allowed_leave_types)}', 400)
        
        # 验证员工是否存在
        employee = Employee.query.filter_by(employee_id=data['applicant_id']).first()
        if not employee:
            return error_response('员工不存在', 404)
        
        # 创建申请记录
        # 解析时长
        leave_hours = None
        if 'leave_hours' in data:
            try:
                leave_hours = float(data['leave_hours'])
            except ValueError:
                return error_response('leave_hours 必须为数字', 400)
            if leave_hours <= 0:
                return error_response('leave_hours 必须大于 0', 400)
        elif 'leave_days' in data:
            # 兼容旧字段，按 1 天=8 小时
            try:
                leave_days_val = float(data['leave_days'])
            except ValueError:
                return error_response('leave_days 必须为数字', 400)
            if leave_days_val <= 0:
                return error_response('leave_days 必须大于 0', 400)
            leave_hours = leave_days_val * 8
        else:
            return error_response('缺少请假时长字段（leave_hours 或 leave_days）', 400)

        # 规范化旧字段值（存库保留原 leave_days 便于兼容）
        leave_days_store = round(leave_hours / 8, 4)

        # 解析开始/结束日期时间，允许多种格式
        def parse_dt(val: str) -> datetime:
            formats = [
                '%Y-%m-%d %H:%M:%S',
                '%Y-%m-%d %H:%M',
                '%Y-%m-%dT%H:%M:%S',
                '%Y-%m-%dT%H:%M',
                '%Y-%m-%d'
            ]
            for fmt in formats:
                try:
                    return datetime.strptime(val, fmt)
                except ValueError:
                    continue
            raise ValueError('时间格式不正确，支持格式: YYYY-MM-DD[ HH:MM[:SS]] 或 ISO8601')

        try:
            start_dt = parse_dt(data['start_date'])
            end_dt = parse_dt(data['end_date'])
        except ValueError as ve:
            return error_response(str(ve), 400)
        if end_dt < start_dt:
            return error_response('结束时间不能早于开始时间', 400)

        # 校验 project_id
        try:
            project_id_val = int(data['project_id'])
        except (ValueError, TypeError):
            return error_response('project_id 必须为整数', 400)

        application = LeaveApplication(
            applicant_id=data['applicant_id'],
            apply_type=data['apply_type'],
            leave_type=leave_type_val,
            leave_days=leave_days_store,
            leave_hours=leave_hours,
            start_date=start_dt,
            end_date=end_dt,
            reason=data.get('reason', ''),
            status='pending',
            project_id=project_id_val
        )
        db.session.add(application)
        db.session.commit()
        print("company", employee.company)
        
        # 查找审批人
        # 1. 查找直接主管（同公司的项目经理）
        manager = Employee.query.filter_by(
            position='项目经理',
            company=employee.company,
            status='active'
        ).first()
        

        if not manager:
            return error_response('未找到审批人（项目经理），请联系管理员', 400)
        
        # 2. 查找HR审批人（同公司的HR主管）
        hr_manager = Employee.query.filter_by(
            position='HR主管',
            company=employee.company,
            status='active'
        ).first()
        
        if not hr_manager:
            return error_response('未找到HR审批人，请联系管理员', 400)
        
        # 启动 Flowable 流程
        try:
            # 注意：这里改为使用员工的 employee_id 作为流程变量传递给 BPMN，
            # Flowable UserTask 的 assignee 仍需是 Flowable IDM 中的有效用户名。
            # 若 Flowable 中的用户体系使用 employee_id 作为用户名，则可以直接使用；
            # 若不是，请在启动流程前确保已同步（或改为 candidateGroups 方式）。
            process_variables = {
                'serviceHost': Config.SERVICE_HOST,
                'applicantId': data['applicant_id'],
                'applyType': data['apply_type'],
                'leaveType': leave_type_val,
                'leaveHours': leave_hours,
                'startDate': data['start_date'],
                'endDate': data['end_date'],
                'reason': data.get('reason', ''),
                'applicationId': application.id,
                'projectId': project_id_val,
                'assignee': manager.employee_id,      # 使用项目经理的 employee_id
                'hrAssignee': hr_manager.employee_id  # 使用 HR 主管的 employee_id
            }
            
            # 使用业务主键编码发起人: <applicantId>:<applicationId>
            bk = f"{employee.employee_id}:{application.id}"
            process_instance = self.flowable_client.start_process_instance(
                process_definition_key='leaveApproval',
                variables=process_variables,
                business_key=bk
            )
            
            # 更新流程实例 ID
            application.process_instance_id = process_instance['id']
            db.session.commit()
            
            return success_response({
                'application': application.to_dict(),
                'process_instance_id': process_instance['id'],
                'business_key': bk
            }, '申请提交成功')
            
        except Exception as e:
            # 回滚数据库事务
            db.session.rollback()
            return error_response(f'启动流程失败: {str(e)}', 500)
    
    @handle_errors
    def get(self):
        """查询申请列表"""
        applicant_id = request.args.get('applicant_id')
        status = request.args.get('status')
        
        query = LeaveApplication.query
        
        if applicant_id:
            query = query.filter_by(applicant_id=applicant_id)
        if status:
            query = query.filter_by(status=status)
        
        applications = query.order_by(LeaveApplication.created_at.desc()).all()
        
        return success_response([app.to_dict() for app in applications])


class LeaveApplicationDetailResource(Resource):
    """请假/加班申请详情资源"""
    
    @handle_errors
    def get(self, application_id):
        """获取申请详情"""
        application = LeaveApplication.query.get(application_id)
        if not application:
            return error_response('申请不存在', 404)
        
        return success_response(application.to_dict())


